package com.kasa.zto;

import java.io.UnsupportedEncodingException;
import java.sql.Time;
import java.util.Date;

/**
 * <p>Title: 解码器</p>
 *
 * <p>Description: </p>
 *
 * <p>Copyright: Copyright (c) 2008</p>
 *
 * <p>Company: </p>
 *
 * @author gary
 * @version 1.0
 */
public abstract class ZTODecoder
{
    public ZTODecoder()
    {
    }
    
    protected byte getByte()
    {
        return getBytes(1)[0];
    }
    
    protected abstract byte[] getBytes(int size);
    
    public abstract long decode_long(byte digit) throws ZTOException;
    
    /**
     * @return 返回值Number只考虑Long型的数据
     * @throws ZTOException
     */
    private Number decodeNumber() throws ZTOException
    {
    	byte digit = decode_byte();
        if(ZTOTag.NULL == digit)
        {
            return null;
        }
        else
        {
            return decode_long(digit);
        }
    }

    public Boolean decodeBoolean() throws ZTOException
    {
        byte b = decode_byte();
        if(0 == b)
        {
            return false;
        }
        else if(1 == b)
        {
            return true;
        }
        else
        {
            return null;
        }
    }

    public Byte decodeByte() throws ZTOException
    {
        byte b = decode_byte();
        if(ZTOTag.NULL == b)
        {
            return null;
        }
        else
        {
            return decode_byte();
        }
    }
    
    public Short decodeShort() throws ZTOException
    {
    	Number n = decodeNumber();
        if(null != n)
        {
        	return n.shortValue();
        }
        return null;
    }

    public Integer decodeInteger() throws ZTOException
    {       
    	Number n = decodeNumber();
        if(null != n)
        {
        	return n.intValue();
        }
        return null;
    }

    public Long decodeLong() throws ZTOException
    {
        Number n = decodeNumber();
        if(null != n)
        {
        	return n.longValue();
        }
        return null;
    }

    public Float decodeFloat() throws ZTOException
    {       
        Number n = decodeNumber();
        if(null != n)
        {
        	return (float) n.longValue() / 1000;
        }
        return null;
    }

    public Double decodeDouble() throws ZTOException
    {
    	Number n = decodeNumber();
        if(null != n)
        {
        	return (double) n.longValue() / 1000;
        }
        return null;
    }

    public boolean decode_boolean() throws ZTOException
    {
        return 0 == decode_byte() ? false : true;
    }

    public byte decode_byte() throws ZTOException
    {
        return getByte();
    }
    
    public byte[] decode_bytes() throws ZTOException
    {
        int byteSize = decode_int();
        if (ZTOTag.NULL == byteSize)
        {
            return null;
        }
        else
        {
            return getBytes(byteSize);
        }
    }
    
    public short decode_short() throws ZTOException
    {
        return (short) decode_long();
    }

    public int decode_int() throws ZTOException
    {
        return (int) decode_long();
    }
    
    public long decode_long() throws ZTOException
    {
    	byte digit = decode_byte();
    	return decode_long(digit);
    	
    	//不建议用下列方法decodeNumber()，否则会有基本数据类型与数字对象间的转换，影响速度
//    	decodeNumber();
    }

    public float decode_float() throws ZTOException
    {
        return (float)decode_long()/1000;
    }

    public double decode_double() throws ZTOException
    {
        return (double)decode_long()/1000;
    }
    
    public String decodeString(String charsetName) throws ZTOException
    {
        int byteSize = decode_int();
        if (ZTOTag.NULL == byteSize)
        {
            return null;
        }
        else if(byteSize < 0)
        {
            return "";
        }
        else
        {
            return decodeString(byteSize, charsetName);
        }
    }

    public String decodeString() throws ZTOException
    {
        int byteSize = decode_int();
        if (ZTOTag.NULL == byteSize)
        {
            return null;
        }
        else if(byteSize < 0)
        {
            return "";
        }
        else
        {
            return decodeString(byteSize);
        }
    }
    
    public String decodeString(int byteSize, String charsetName) throws ZTOException
    {
        try {
			return new String(getBytes(byteSize), charsetName);
		} catch (UnsupportedEncodingException e) {
			return new String(getBytes(byteSize));
		}
    }

    /**
     * 以当前pos位置，解码byteSize个字节为字符串
     * @param byteSize int
     * @return String
     * @throws ZTOException
     */
    public String decodeString(int byteSize) throws ZTOException
    {
        return new String(getBytes(byteSize));
    }

    public Date decodeDate() throws ZTOException
    {
        Long l = decodeLong();
        if (null == l)
        {
            return null;
        }
        else
        {
            return new Date(l);
        }
    }

    public Time decodeTime() throws ZTOException
    {
        Long l = decodeLong();
        if (null == l)
        {
            return null;
        }
        else
        {
            return new Time(l);
        }
    }

    public <T extends ZTOType> T decodeZTOType(Class<? extends T> ztoTypeClass) throws ZTOException
    {
        byte tag = decode_byte();
        switch (tag)
        {
            case ZTOTag.NULL:
            {
                return null;
            }
            case ZTOTag.ZTOType:
            {
                try
                {
                    T t = ztoTypeClass.newInstance();
                    t.decode(this);
                    return t;
                }
                catch (Exception e)
                {
                    throw new ZTOException(e);
                }
            }
            default:
            {
                throw new ZTOException("tag == " + tag + " in decodeZTOType");
            }
        }
    }

    public ZTOAny decodeZTOAny() throws ZTOException
    {
        byte tag = decode_byte();
        switch (tag)
        {
            case ZTOTag.NULL:
            {
                return null;
            }
            case ZTOTag.ZTOAny:
            {
                ZTOAny any = new ZTOAny();
                any.decode(this);
                return any;
            }
            default:
            {
                throw new ZTOException("tag == " + tag + " in decodeZTOAny");
            }
        }
    }

    public <T extends ZTOType> ZTOArrayList<T> decodeZTOArrayList(Class<? extends T> elementClass) throws ZTOException
    {
        byte tag = decode_byte();
        switch (tag)
        {
            case ZTOTag.NULL:
            {
                return null;
            }
            case ZTOTag.ZTOArrayList:
            {
                ZTOArrayList<T> list = new ZTOArrayList<T>(elementClass);
                list.decode(this);
                return list;
            }
            default:
            {
                throw new ZTOException("tag == " + tag + " in decodeZTOArrayList");
            }
        }
    }
    
    public <K extends ZTOType, V extends ZTOType> ZTOLinkedHashMap<K, V> decodeZTOLinkedHashMap(Class<? extends K> keyClass, Class<? extends V> valueClass) throws ZTOException
    {
        byte tag = decode_byte();
        switch (tag)
        {
            case ZTOTag.NULL:
            {
                return null;
            }
            case ZTOTag.ZTOLinkedHashMap:
            {
                ZTOLinkedHashMap<K, V> map = new ZTOLinkedHashMap<K, V>(keyClass, valueClass);
                map.decode(this);
                return map;
            }
            default:
            {
                throw new ZTOException("tag == " + tag + " in decodeZTOLinkedHashMap");
            }
        }
    }
}
